﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Microsoft.Expression.Encoder;
using VideoEncoder.Properties;
using Microsoft.Expression.Encoder.Profiles;
using System.Windows.Threading;
using System.Runtime.Remoting.Messaging;

namespace VideoEncoder
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static MainWindow Default { get; set; }

        string[] extensions = new string[] { ".mov", ".avi", ".mpeg", ".mpg", ".mkv", ".mp4", ".dvr-ms", ".m2ts", ".ts" };

        public ObservableCollection<MediaEncoder> Queue { get; set; }

        MediaEncoder currentEncoder;
        //VideoProfile vProfile = null;
        //AudioProfile aProfile = null;
        ObservableCollection<AudioProfile> AudioProfiles;
        ObservableCollection<VideoProfile> VideoProfiles;
        private List<VideoComplexity> videoComplexity;

        public MainWindow()
        {
            InitializeComponent();

            Queue = new ObservableCollection<MediaEncoder>();
            AudioProfiles = new ObservableCollection<AudioProfile>();
            VideoProfiles = new ObservableCollection<VideoProfile>();
            itemsQueueDataGrid.SelectionChanged += new SelectionChangedEventHandler(itemsQueueDataGrid_SelectionChanged);
            itemsQueueDataGrid.ItemsSource = Queue;

            sourceBrowseButton.Click += new RoutedEventHandler(sourceBrowseButton_Click);
            outputBrowseButton.Click += new RoutedEventHandler(outputBrowseButton_Click);
            startButton.Click += new RoutedEventHandler(startButton_Click);
            cancelButton.Click += new RoutedEventHandler(cancelButton_Click);
            loadButton.Click += new RoutedEventHandler(loadButton_Click);
            pauseButton.Click += new RoutedEventHandler(pauseButton_Click);
            resumeButton.Click += new RoutedEventHandler(resumeButton_Click);
            addFileButton.Click += new RoutedEventHandler(addFileButton_Click);

            sameAsSourceCheckBox.Click += new RoutedEventHandler(sameAsSourceCheckBox_Click);
            deleteSourceCheckBox.Click += new RoutedEventHandler(sameAsSourceCheckBox_Click);
            closeCheckBox.Click += new RoutedEventHandler(sameAsSourceCheckBox_Click);


            videoComplexity = new List<VideoComplexity>();
            videoComplexity.Add(VideoComplexity.Fastest);
            videoComplexity.Add(VideoComplexity.Fast);
            videoComplexity.Add(VideoComplexity.Good);
            videoComplexity.Add(VideoComplexity.Normal);
            videoComplexity.Add(VideoComplexity.Better);
            videoComplexity.Add(VideoComplexity.Best);

            videoComplexityCombo.ItemsSource = videoComplexity;
            videoComplexityCombo.SelectionChanged += new SelectionChangedEventHandler(videoComplexityCombo_SelectionChanged);

            videoProfileCombo.SelectionChanged += new SelectionChangedEventHandler(videoProfileCombo_SelectionChanged);
            audioProfileCombo.SelectionChanged += new SelectionChangedEventHandler(audioProfileCombo_SelectionChanged);

            MainWindow.Default = this;

            Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }
        void sameAsSourceCheckBox_Click(object sender, RoutedEventArgs e)
        {
            outputTextBox.IsEnabled = outputBrowseButton.IsEnabled = !sameAsSourceCheckBox.IsChecked.Value;
            Settings.Default.Save();
        }

        void videoComplexityCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox combo = sender as ComboBox;
            if (combo.SelectedIndex == -1)
                combo.SelectedIndex = 0;
            Settings.Default.DefaultVideoComplexity = combo.SelectedIndex;
            Settings.Default.Save();
        }

        void addFileButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog dg = new System.Windows.Forms.OpenFileDialog();
            dg.Filter = "Media Files|*.mov;*.avi;*.mpeg;*.mpg;*.mkv;*.mp4;*.dvr-ms;*.m2ts;*.ts";
            dg.Multiselect = true;
            if (dg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {

                if (videoProfileCombo.SelectedIndex == -1)
                    throw new ApplicationException("A video profile has to be selected");

                if (audioProfileCombo.SelectedIndex == -1)
                    throw new ApplicationException("An audio profile has to be selected");

                foreach (string filename in dg.FileNames)
                {
                    FileInfo file = new FileInfo(filename);
                    AddFile(file);
                }
            }
        }

        void resumeButton_Click(object sender, RoutedEventArgs e)
        {
            if (currentEncoder != null)
                currentEncoder.Resume();
            pauseButton.Visibility = Visibility.Visible;
            resumeButton.Visibility = Visibility.Collapsed;
        }

        void pauseButton_Click(object sender, RoutedEventArgs e)
        {
            if (currentEncoder != null)
                currentEncoder.Pause();
            pauseButton.Visibility = Visibility.Collapsed;
            resumeButton.Visibility = Visibility.Visible;
        }

        void audioProfileCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox combo = sender as ComboBox;
            if (combo.SelectedIndex == -1)
                combo.SelectedIndex = 0;
            Settings.Default.DefaultAudioProfile = combo.SelectedIndex;
            Settings.Default.Save();
        }

        void videoProfileCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox combo = sender as ComboBox;
            if (combo.SelectedIndex == -1)
                combo.SelectedIndex = 0;
            Settings.Default.DefaultVideoProfile = combo.SelectedIndex;
            Settings.Default.Save();
        }

        void itemsQueueDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            MediaEncoder encoder = itemsQueueDataGrid.SelectedItem as MediaEncoder;
            if (encoder == null)
            {
                selectedMediaItemGrid.Visibility = Visibility.Collapsed;
                return;
            }

            videoProfile.MediaItem = encoder.MediaItem;
            audioProfile.MediaItem = encoder.MediaItem;
            projectedFileSizeTextBlock.DataContext = encoder.MediaItem;
            selectedMediaItemGrid.Visibility = Visibility.Visible;

        }

        void loadButton_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(Settings.Default.SourceFolder))
            {
                MessageBox.Show("Please select a source folder.");
                return;
            }
            DirectoryInfo di = new DirectoryInfo(Settings.Default.SourceFolder);
            AddFilesToQueue(di);
        }

        void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (currentEncoder != null)
                currentEncoder.Cancel();
            pauseButton.Visibility = Visibility.Collapsed;
            resumeButton.Visibility = Visibility.Collapsed;
            cancelButton.Visibility = Visibility.Collapsed;
            startButton.Visibility = Visibility.Visible;
        }

        void startButton_Click(object sender, RoutedEventArgs e)
        {

            if (string.IsNullOrEmpty(Settings.Default.OutputFolder) && !Settings.Default.OutputSameAsSource)
            {
                MessageBox.Show("Please select an output folder.");
                return;
            }

            ProcessQueue();
        }

        private void ProcessQueue()
        {
            if (Queue.Where(p => p.Status == ItemStatus.Ready).Count() > 0)
            {
                currentEncoder = Queue.Where(p => p.Status == ItemStatus.Ready).FirstOrDefault();
                if (Settings.Default.OutputSameAsSource)
                    currentEncoder.OutputDirectory = currentEncoder.File.DirectoryName;
                else
                    currentEncoder.OutputDirectory = Settings.Default.OutputFolder;

                if (File.Exists(currentEncoder.TargetFile))
                {
                    MessageBoxResult result = MessageBox.Show("The target file already exists, overwrite?", "Overwrite?", MessageBoxButton.YesNoCancel);
                    if (result == MessageBoxResult.Yes)
                        File.Delete(currentEncoder.TargetFile);
                    else if (result == MessageBoxResult.No)
                    {
                        currentEncoder.Status = ItemStatus.Error;
                        ProcessQueue();
                        return;
                    }
                    else if (result == MessageBoxResult.Cancel)
                        return;

                }
                if (currentEncoder != null)
                {
                    currentEncoder.DeleteFile = Settings.Default.DeleteSource;
                    currentEncoder.Encode();
                }

                pauseButton.Visibility = Visibility.Visible;
                cancelButton.Visibility = Visibility.Visible;
                startButton.Visibility = Visibility.Collapsed;

            }
            else
            {
                pauseButton.Visibility = Visibility.Collapsed;
                resumeButton.Visibility = Visibility.Collapsed;
                cancelButton.Visibility = Visibility.Collapsed;
                startButton.Visibility = Visibility.Visible;
                if (Settings.Default.CloseWhenComplete)
                    Application.Current.Shutdown();

            }

        }

        private void AddFilesToQueue(DirectoryInfo dir)
        {
            defaultProfilesExpander.IsExpanded = false;
            if (videoProfileCombo.SelectedIndex == -1)
                throw new ApplicationException("A video profile has to be selected");

            if (audioProfileCombo.SelectedIndex == -1)
                throw new ApplicationException("An audio profile has to be selected");


            foreach (FileInfo file in dir.GetFiles())
            {
                AddFile(file);
            }
            foreach (DirectoryInfo dir2 in dir.GetDirectories())
                AddFilesToQueue(dir2);
        }

        private void AddFile(FileInfo file)
        {
            VideoProfile vProfile = VideoProfiles[videoProfileCombo.SelectedIndex];
            AudioProfile aProfile = AudioProfiles[audioProfileCombo.SelectedIndex];
            VideoComplexity vcomplexity = videoComplexity[videoComplexityCombo.SelectedIndex];
            if (extensions.Contains(file.Extension) && Queue.Count(m => m.File.FullName == file.FullName) == 0)
            {
                try
                {
                    MediaEncoder encoder = new MediaEncoder(file.FullName, vProfile, aProfile, vcomplexity);
                    encoder.OnEncodeCompleted += new EventHandler(encoder_OnEncodeCompleted);
                    encoder.OnError += new ErrorEventHandler(encoder_OnError);
                    encoder.OnProgressChanged += new EventHandler(encoder_OnProgressChanged);
                    Queue.Add(encoder);
                    //itemsQueueListBox.ItemsSource = queue;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        void encoder_OnProgressChanged(object sender, EventArgs e)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate()
                {
                    MediaEncoder encoder = sender as MediaEncoder;
                    if (string.IsNullOrEmpty(encoder.ProgressText))
                        Title = "Video Encoder";
                    else
                        Title = encoder.ProgressText;
                });
        }

        void encoder_OnError(object sender, string message)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate()
                    {
                        MessageBox.Show(message);
                    });
        }

        void encoder_OnEncodeCompleted(object sender, EventArgs e)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate()
                    {
                        Title = "Video Encoder";
                        MediaEncoder encoder = sender as MediaEncoder;
                        if (encoder != null)
                        {
                            if (!encoder.IsCanceled)
                                ProcessQueue();
                            else
                            {

                                pauseButton.Visibility = Visibility.Collapsed;
                                resumeButton.Visibility = Visibility.Collapsed;
                                cancelButton.Visibility = Visibility.Collapsed;
                                startButton.Visibility = Visibility.Visible;

                            }
                        }
                    });
        }

        void outputBrowseButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();

            if (!string.IsNullOrEmpty(Settings.Default.OutputFolder))
                dialog.SelectedPath = Settings.Default.OutputFolder;

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Settings.Default.OutputFolder = dialog.SelectedPath;
                Settings.Default.Save();
            }
        }

        void sourceBrowseButton_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();

            if (!string.IsNullOrEmpty(Settings.Default.SourceFolder))
                dialog.SelectedPath = Settings.Default.SourceFolder;

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Settings.Default.SourceFolder = dialog.SelectedPath;
                Settings.Default.Save();
            }
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            LoadProfilesDel del = new LoadProfilesDel(LoadProfiles);
            del.BeginInvoke(new AsyncCallback(LoadProfilesCallBack),null);
        }

        delegate void LoadProfilesDel();
        void LoadProfiles()
        {
            VideoProfile videoPro = null;
            AudioProfile audioPro = null;

            DirectoryInfo dir = new DirectoryInfo(System.IO.Path.Combine(Environment.CurrentDirectory, "Profiles"));
            foreach (FileInfo file in dir.GetFiles("*.xml"))
            {
                LocalProfiles.LoadProfileFromFile(file.FullName, out videoPro, out audioPro);
                if (videoPro != null)
                    VideoProfiles.Add(videoPro);
                if (audioPro != null)
                    AudioProfiles.Add(audioPro);
            }
            foreach (FileInfo file in dir.GetFiles("*.prx"))
            {
                LocalProfiles.LoadProfileFromFile(file.FullName, out videoPro, out audioPro);
                
                if (videoPro != null)
                    VideoProfiles.Add(videoPro);
                if (audioPro != null)
                    AudioProfiles.Add(audioPro);                
            }

            audioProfile.AudioProfiles = AudioProfiles;
            videoProfile.VideoProfiles = VideoProfiles;

            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate()
                    {
                        DataContext = Settings.Default;                        

                        videoProfileCombo.ItemsSource = VideoProfiles;
                        audioProfileCombo.ItemsSource = AudioProfiles;

                        videoProfileCombo.SelectedIndex = Settings.Default.DefaultVideoProfile;
                        audioProfileCombo.SelectedIndex = Settings.Default.DefaultAudioProfile;

                        videoComplexityCombo.SelectedIndex = Settings.Default.DefaultVideoComplexity;

                        outputTextBox.IsEnabled = outputBrowseButton.IsEnabled = !Settings.Default.OutputSameAsSource;
                        rootGrid.Visibility = Visibility.Visible;
                        loadingGrid.Visibility = Visibility.Collapsed;
                    });
        }
        void LoadProfilesCallBack(IAsyncResult ar)
        {
            LoadProfilesDel worker = (LoadProfilesDel)((AsyncResult)ar).AsyncDelegate;
            worker.EndInvoke(ar);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            MediaEncoder encoder = button.Tag as MediaEncoder;
            if (encoder.Status != ItemStatus.Encoding)
                Queue.Remove(encoder);
            e.Handled = true;
        }

        private void MoveUp_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            MediaEncoder encoder = button.Tag as MediaEncoder;
            int index = Queue.IndexOf(encoder);
            if (index > 0)
                Queue.Move(index, index - 1);
            e.Handled = true;
        }

        private void MoveDown_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            MediaEncoder encoder = button.Tag as MediaEncoder;
            int index = Queue.IndexOf(encoder);
            if (index < Queue.Count - 1)
                Queue.Move(index, index + 1);
            e.Handled = true;
        }
    }
}
